﻿#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<exception>
using namespace std;

#if 0
//下面的三个  try   catch   但还是跳到了最后一个（最后一个捕获  因为类型匹配）
double Divide(int a, int b)
{
	try
	{
		//当 b == 0 时    抛出异常
		if (b == 0)
		{
			string s("Dovide by zero condition!");
			throw s;
	
	// 如果下面这个语句放在这里   那么这个代码是永远都执行不到的   因为抛出就会跳走（执行流跳走）
	// cout << __FUNCTION__ << ":" << __LINE__ << "行执行" << endl;

		}

		else
		{
			return ((double)a / (double)b);
		}
	}
	catch (int errid)
	{
		cout << errid << endl;
	}
	return 0;
}

void Func()
{
	int len, time;
	cin >> len >> time;

	try
	{
		cout << Divide(len, time) << endl;
	}

	catch (const char* errmsg)		//注意：这里如果也是类型匹配的  那么就会调用这个  catch(const string& errmsg)
	//catch(const string& errmsg)
	{
		cout << errmsg << endl;
	}

	cout << __FUNCTION__ << ":" << __LINE__ << "行执行" << endl;
}								//代表   哪一行执行

int main()
{
	while (1)
	{
		try
		{
			Func();
		}
		catch (const string& errmsg)    //如果上面虽然接近  但是类型并不匹配  就还是会调用这里的这个
		{
			cout << errmsg << endl;
		}

	//这就是  捕获任意类型异常     任意类型异常
		catch(...)
		{
			cout << "未知异常" << endl;
		}
	//都没有   才会适配这个
	}
	return 0;
}

//抛异常的话    类型必须要匹配    抛string，需要使用string进行捕获     
//而且是  距离最近的那一个

//如果正常  就可以正常的输出跳过catch
//如果非正常，就会调到适配类型的catch   进行捕获   然后如果没有就近捕捉，后续的代码不会执行，并跳到对应的地方，然后捕捉，会正常销毁栈帧

/*  异常可以适用  catch(...){ }  进行任意类型（未知异常）的捕获   不知道什么类型的异常   但是程序并不会挂  */

#endif




#if 0

#include<thread>
// 一般大型项目程序才会使用异常，模拟设计一个服务的几个模块 
// 每个模块的继承都是Exception的派生类，每个模块可以添加自己的数据 
// 最后捕获时，我们捕获基类就可以 
class Exception
{
public:
	Exception(const string& errmsg, int id)
		:_errmsg(errmsg)     //错误信息   错误编号
		, _id(id)
	{}

	//返回错误信息的虚函数
	virtual string what() const
	{
		return _errmsg;
	}

	//返回错误编号
	int getid() const
	{
		return _id;
	}

protected:
	string _errmsg;
	int _id;
};

//SqlException需要是Exception的派生类   
class SqlException : public Exception
{
public:
	//sql的Exception 的构造
	SqlException(const string& errmsg, int id, const string& sql)
		:Exception(errmsg, id)
		, _sql(sql)
	{}

	// 返回错误信息的虚函数
	virtual string what() const
	{
		string str = "SqlException:";
		str += _errmsg;
		str += "->";
		str += _sql;
		return str;
	}

private:
	const string _sql;
};

class CacheException : public Exception
{
public:
	CacheException(const string& errmsg, int id)
		:Exception(errmsg, id)
	{}

	//虚函数
	virtual string what() const
	{
		string str = "CacheException:";
		str += _errmsg;
		return str;
	}
};

//http的错误
class HttpException : public Exception
{
public:
	HttpException(const string& errmsg, int id, const string& type)
		:Exception(errmsg, id)
		, _type(type)
	{}

	virtual string what() const
	{
		string str = "HttpException:";
		str += _type;
		str += ":";
		str += _errmsg;
		return str;
	}

private:
	const string _type;
};

void SQLMgr()
{
	if (rand() % 7 == 0)
	{
		throw SqlException("权限不足", 100, "select * from name = '张三'");
	}

	else
	{
		cout << "SQLMgr 调用成功" << endl;
	}
}

void CacheMgr()
{
	if (rand() % 5 == 0)
	{
		throw CacheException("权限不足", 100);
	}

	else if (rand() % 6 == 0)
	{
		throw CacheException("数据不存在", 101);
	}

	else
	{
		cout << "CacheMgr 调用成功" << endl;
	}

	SQLMgr();
}

void HttpServer()
{
	if (rand() % 3 == 0)
	{
		throw HttpException("请求资源不存在", 100, "get");
	}

	else if (rand() % 4 == 0)
	{
		throw HttpException("权限不足", 101, "post");
	}

	else
	{
		cout << "HttpServer调用成功" << endl;
	}

	CacheMgr();
}

//int main()
//{
//	srand(time(0));
//	while (1)
//	{
//		this_thread::sleep_for(chrono::seconds(1));
//		try 
//		{
//			HttpServer();
//		}
//		
//		catch (const Exception& e) // 这⾥捕获基类，基类对象和派⽣类对象都可以被捕获
//		{
//			cout << e.what() << endl;
//		}
//
//		catch (...)
//		{
//			cout << "Unkown Exception" << endl;
//		}
//	}
//	return 0;
//}




// 下⾯程序模拟展⽰了聊天时发送消息，发送失败补货异常，但是可能在 
// 电梯地下室等场景⼿机信号不好，则需要多次尝试，如果多次尝试都发 
// 送不出去，则就需要捕获异常再重新抛出，其次如果不是⽹络差导致的 
// 错误，捕获后也要重新抛出。 
void _SeedMsg(const string& s)
{
	if (rand() % 2 == 0)
	{
		throw HttpException("网络不稳定，发送失败", 102, "put");
	}
	else if (rand() % 7 == 0)
	{
		throw HttpException("你已经不是对象的好友，发送失败", 103, "put");
	}
	else
	{
		cout << "发送成功" << endl;
	}
}

void SendMsg(const string& s)
{
	// 发送消息失败，则再重试3次 
	for (size_t i = 0; i < 4; i++)
	{
		try
		{
			_SeedMsg(s);
			break;
		}

		catch (const Exception& e)
		{
			// 捕获异常，if中是102号错误，网络不稳定，则重新发送 
			// 捕获异常，else中不是102号错误，则将异常重新抛出 
			if (e.getid() == 102)
			{
				// 重试三次以后否失败了，则说明网络太差了，重新抛出异常 
				if (i == 3)
					throw;
				cout << "开始第" << i + 1 << "重试" << endl;
			}

			else
			{
				//重新抛出
				throw;
			}
		}
	}
}

int main()
{
	srand(time(0));
	string str;
	while (cin >> str)
	{
		try
		{
			SendMsg(str);
		}
		catch (const Exception& e)
		{
			cout << e.what() << endl << endl;
		}
		catch (...)
		{
			cout << "Unkown Exception" << endl;
		}
	}
	return 0;
}

#endif